
public class Ship {

    private int angleDir, counter;
    private long m, F_me_max, F_me, F_be, F_res, F_nitro, C_res, K, powerStep, lPosX, lPosY;

    public boolean turnengineIsWorking, isFrontTargetLocked, isRearTargetLocked, wasHit, wasShipHit, 
                   shipVisible, healthVisible,
                   shieldActive, nitroActive, killerActive;
    public long A, V, dS, racingTime;
    public byte controlType, angle, shipState, bodyState, turnState, dir, turnMinAngle, turnMaxAngle, 
                leftDistance, rightDistance, frontDistance, frontShipDistance,
                obstacleType,
                locationAlienShip,
                type, 
                moveMode,
                itemType, weaponType, weaponCount, powerupType, powerupCount,
                healthMeterWidth;
    public int borderFirstIndex, firstTrackItem,
               stepX, stepY, posX, posY, leftPosX, leftPosY, rightPosX, rightPosY, startPosX, startPosY, 
               borderInFrontIndex, nearestTrackItem,
               step,
               money, health;

    public Animation aBody, aShield;
    private Timer healthTimer, shieldTimer, nitroTimer, killerTimer;
    public Shooter shooter;

   
/**************************************************************************************************/

    Ship(byte controlType, byte type, int x, int y) {
        this.controlType = controlType;
        this.type = type;
        startPosX = x;
        startPosY = y;

        m = GameScreen.fpDiv(GameScreen.fpToFP(1), GameScreen.fpToFP(Constants.MASS[type]));
        F_me_max = GameScreen.fpToFP(Constants.MAIN_ENGINE_MAX_POWER[type]);
        C_res = GameScreen.fpDiv(GameScreen.fpToFP(Constants.C_RES), GameScreen.fpToFP(10));

        K = GameScreen.fpDiv(GameScreen.fpToFP(1), GameScreen.fpToFP(1000));

        powerStep = F_me_max / Constants.SHIP_POWER_COUNT_STEPS;

        aBody = new Animation();
        aShield = new Animation();
        healthTimer = new Timer();
        shieldTimer = new Timer();
        nitroTimer = new Timer();
        killerTimer = new Timer();

        shooter = new Shooter();
    }

/**************************************************************************************************/

    public void init(int x, int y) {
        turnState = Constants.SHIP_TURNSTATE_FREE;
        bodyState = (byte)(Constants.SHIP_ANIMATIONS[type].length >> 1);
        counter = bodyState << Constants.SHIP_TS;

        F_me = 0;
        F_be = 0;
        F_nitro = 0;
        A = 0;
        V = 0;
        dS = 0;
        posX = x;
        posY = y;

        updateShipEdges();

        lPosX = GameScreen.fpToFP(posX);
        lPosY = GameScreen.fpToFP(posY);
        stepX = 0;
        stepY = 0;
        angle = 0;
        step = 0;

        turnengineIsWorking = false;
        wasHit = false;
        wasShipHit = false;
        shipVisible = true;
        healthVisible = false;
        shieldActive = false;
        nitroActive = false;
        killerActive = false;

        dir = 0;

        borderFirstIndex = 0;

        firstTrackItem = 0;

        shipState = Constants.SHIP_STATE_READY;
        moveMode = Constants.SHIP_MODE_FLY;

        itemType = Constants.ITEM_NONE;
        health = Constants.SHIP_HEALTH[type];
        money = 0;
        weaponType = Constants.WEAPON_NONE;
        weaponCount = 0;
        powerupCount = 0;
        shooter.init();

        healthTimer.unSet();
        shieldTimer.unSet();
        nitroTimer.unSet();
        killerTimer.unSet();

        aBody.startAnimation(Constants.SHIP_FREE_ANIMATIONS[type][bodyState], Constants.ANIMATION_PLAY_REPEAT);
    }

/**************************************************************************************************/

    private void activateWeapon() {
        if (weaponType != Constants.WEAPON_NONE) shooter.activate(Constants.WEAPON_DECREASE_STEP[weaponType], Constants.WEAPON_POWER[weaponType]);
    }

/**************************************************************************************************/

    public void increaseMainEnginePower() {
        if ((shipState == Constants.SHIP_STATE_MOVE) && (step < Constants.SHIP_POWER_COUNT_STEPS)) {
            step++;
            F_me += powerStep;
        }
    }

/**************************************************************************************************/

   public void decreaseMainEnginePower()
   {
      if((shipState == Constants.SHIP_STATE_MOVE) && (step > 0))
      {
         step--;
         F_me -= powerStep;
      }
   }

/**************************************************************************************************/
/*
    public void stopMainEngine() {
        step = 0;
        F_me = 0;
    }
*/
/**************************************************************************************************/

    public long getBrakeForce(int distance) {
        return GameScreen.fpDiv(GameScreen.fpMul(V, V), GameScreen.fpMul(m, GameScreen.fpToFP(distance)));
    }

/**************************************************************************************************/

    public void startBrakeEngine() {
        startBrakeEngine(GameScreen.fpToFP(Constants.FORCES_BRAKE_ENGINE[type]));
    }

/**************************************************************************************************/

    public void startBrakeEngine(long value) {
        //stopMainEngine();
        step = 0;
        F_me = 0;
        F_be = value;
    }

/**************************************************************************************************/

    public void stopBrakeEngine() {
        F_be = 0;
    }

/**************************************************************************************************/

    public void startRightEngine() {
        startRightEngine(Constants.SHIP_MAX_ANGLE);
    }

    public void startRightEngine(byte turnAngle) {
        if ((!turnengineIsWorking) && (shipState == Constants.SHIP_STATE_MOVE)) {
            turnengineIsWorking = true;
            turnMaxAngle = turnAngle;
            dir = Constants.DIRECTION_RIGHT;
            angleDir = dir;
            turnState = Constants.SHIP_TURNSTATE_MOVE;
        }
    }

/**************************************************************************************************/

    public void startLeftEngine() {
        startLeftEngine((byte)-Constants.SHIP_MAX_ANGLE);
    }

    public void startLeftEngine(byte turnAngle) {
        if ((!turnengineIsWorking) && (shipState == Constants.SHIP_STATE_MOVE)) {
            turnengineIsWorking = true;
            turnMinAngle = turnAngle;
            dir = Constants.DIRECTION_LEFT;
            angleDir = dir;
            turnState = Constants.SHIP_TURNSTATE_MOVE;
        }
    }

/**************************************************************************************************/

    public void stopTurnEngine(byte s) {
        if ((turnengineIsWorking) || (s == Constants.SHIP_TURNSTATE_HITS)) {
            turnengineIsWorking = false;
            turnMinAngle = -Constants.SHIP_MAX_ANGLE;
            turnMaxAngle = Constants.SHIP_MAX_ANGLE;
            angleDir = -dir;
            turnState = s;
            counter = (Constants.SHIP_ANIMATIONS[type].length >> 1) << Constants.SHIP_TS;
        }
    }

/**************************************************************************************************/

    private void impulseExchange(Ship otherShip) {
        long shipNewV, othershipNewV;

        shipNewV = GameScreen.fpMul(GameScreen.fpMul(GameScreen.fpToFP(Constants.MASS[otherShip.type]), m), otherShip.V);
        othershipNewV = GameScreen.fpMul(GameScreen.fpMul(GameScreen.fpToFP(Constants.MASS[type]), otherShip.m), V);
        V = shipNewV;
        otherShip.V = othershipNewV;
    }

/**************************************************************************************************/

    public byte detectCollosionWithLine(int aX, int aY, int bX, int bY) {
        if (leftPosX < GameScreen.max(aX, bX) && rightPosX > GameScreen.min(aX, bX) && leftPosY < bY && posY > aY) {
            if (GameScreen.isIntersection(posX, posY, leftPosX, leftPosY, aX, aY, bX, bY)) {
                return Constants.SHIP_LEFT_SIDE;
            }
            else if (GameScreen.isIntersection(posX, posY, rightPosX, rightPosY, aX, aY, bX, bY))
            {
                return Constants.SHIP_RIGHT_SIDE;
            }
        }
        return -1;
    }

/**************************************************************************************************/

    public int detectEdgeCollision() {
        int i, tInt, h;
        short aPosX, aPosY, bPosX, bPosY;
        byte res, mode;

        mode = 0;
        for (i = borderFirstIndex; i < GameScreen.borders.length; i++) {
            aPosX = GameScreen.borders[i].aPosX;
            aPosY = GameScreen.borders[i].aPosY;
            bPosX = GameScreen.borders[i].bPosX;
            bPosY = GameScreen.borders[i].bPosY;

            if ((i == borderFirstIndex) && (bPosY < leftPosY)) {
                borderFirstIndex ++;
            }
            else {
                if (mode == 0) {
                    if (aPosY > posY) {
                        if ((controlType == Constants.SHIP_NPC)) mode = 1;
                        else break;
                    }
                    else {
                        // Detect collision with ship
                        if ((aPosY <= leftPosY) && (leftPosY <= bPosY)) {
                            if (GameScreen.borders[i].side == 0) {
                                // | <- /\
                                if (aPosX == bPosX) {
                                    // The edges is vertical
                                    tInt = leftPosX - aPosX;
                                    if (tInt < leftDistance) leftDistance = (byte)tInt;
                                }
                                else {
                                    tInt = GameScreen.getCrossPoint(GameScreen.min(aPosX, bPosX), leftPosY, leftPosX, leftPosY, aPosX, aPosY, bPosX, bPosY);
                                    tInt = leftPosX - ((tInt << 1) >> 17);
                                    if (tInt < leftDistance) leftDistance = (byte)tInt;
                                }
                            }
                            else if (GameScreen.borders[i].side == 1) {
                                // /\ -> |
                                if (aPosX == bPosX) {
                                    // The edges is vertical
                                    tInt = aPosX - rightPosX;
                                    if (tInt < rightDistance) rightDistance = (byte)tInt;
                                }
                                else {
                                    tInt = GameScreen.getCrossPoint(rightPosX, rightPosY, GameScreen.max(aPosX, bPosX), rightPosY, aPosX, aPosY, bPosX, bPosY);
                                    tInt = ((tInt << 1) >> 17) - rightPosX;
                                    if (tInt < rightDistance) rightDistance = (byte)tInt;
                                }
                            }
                        }

                        res = detectCollosionWithLine(aPosX, aPosY, bPosX, bPosY);
                        if (res > -1) {
                            return ((res << 16) & 0xFFFF0000) | (i & 0x0000FFFF);
                        }
                    }
                }

                if (controlType == Constants.SHIP_NPC) {
                    h = (posY + Constants.SHIP_RADAR_DISTANCE);
                    if ((mode == 1) && (aPosY > h)) {
                        break;
                    }
                    else {
                        switch (GameScreen.borders[i].type) {
                            case Constants.BORDER_TRACKEDGE:
                                if ((GameScreen.borders[i].side == 0) && (aPosX < bPosX)) {
                                    if (leftPosX < bPosX && rightPosX > aPosX && leftPosY < bPosY && h > aPosY) {
                                        tInt = GameScreen.getCrossPoint(leftPosX, posY, leftPosX, h, aPosX, aPosY, bPosX, bPosY);
                                        tInt = (tInt & 0x0000ffff) - posY;
                                        if (tInt < frontDistance) {
                                            obstacleType = Constants.OBSTACLE_EDGE;
                                            frontDistance = (byte)tInt;
                                            borderInFrontIndex = i;
                                        }
                                    }
                                }
                                else if ((GameScreen.borders[i].side == 1) && (aPosX > bPosX)) {
                                    if(leftPosX < aPosX && rightPosX > bPosX && leftPosY < bPosY && h > aPosY) {
                                        tInt = GameScreen.getCrossPoint(rightPosX, posY, rightPosX, h, aPosX, aPosY, bPosX, bPosY);
                                        tInt = (tInt & 0x0000ffff) - posY;
                                        if (tInt < frontDistance) {
                                            obstacleType = Constants.OBSTACLE_EDGE;
                                            frontDistance = (byte)tInt;
                                            borderInFrontIndex = i;
                                        }
                                    }
                                }
                            break;
                            
                            case Constants.BORDER_WALL:
                                if (leftPosX < bPosX && rightPosX > aPosX && leftPosY < bPosY && h > aPosY) {
                                    tInt = aPosY - posY;
                                    if (tInt < frontDistance) {
                                        obstacleType = Constants.OBSTACLE_WALL;
                                        frontDistance = (byte)tInt;
                                        borderInFrontIndex = i;
                                    }
                                }
                            break;
                            
                            case Constants.BORDER_JUMP:
                            break;
                        }
                    }
                }
            }
        }
        return 0;
    }

/**************************************************************************************************/

    public boolean detectShipCollision(Ship otherShip) {
        int x, y, left_x, left_y, right_x, right_y, tInt;
        byte res;

        if (shipState != Constants.SHIP_STATE_DESTROYED && shipState != Constants.SHIP_STATE_REINIT && otherShip.shipState != Constants.SHIP_STATE_DESTROYED && otherShip.shipState != Constants.SHIP_STATE_REINIT && (moveMode == otherShip.moveMode)) {
            x = otherShip.posX;
            y = otherShip.posY;
            left_x = otherShip.leftPosX;
            left_y = otherShip.leftPosY;
            right_x = otherShip.rightPosX;
            right_y = otherShip.rightPosY;

            if (leftPosX < right_x && rightPosX > left_x && leftPosY < y && posY > left_y) {
                if ((left_x < posX) && (posX < right_x) && (left_y < posY) && (leftPosY < left_y)) {
                    if (killerActive) {
                        otherShip.destroyShip();
                    }
                    else {
                        impulseExchange(otherShip);
                    }
                }
                else if (x < posX) {
                    // Other ship is on the left side \<-/\
                    res = detectCollosionWithLine(right_x, right_y, x, y);
                    if (res > -1) {
                        if (killerActive) otherShip.destroyShip();
                        else {
                            wasShipHit = true;
                            otherShip.wasShipHit = true;
                            processCollision(res, right_x, right_y, x, y, (byte)30, (byte)0);
                            otherShip.processCollision(Constants.SHIP_RIGHT_SIDE, leftPosX, leftPosY, posX, posY, (byte)-30, (byte)1);
                       
                            impulseExchange(otherShip);
                       
                            return true;
                        }
                    }
                }
                else if (x > posX) {
                    // Other ship is on the right side /\->/
                    wasShipHit = true;
                    otherShip.wasShipHit = true;
                    res = detectCollosionWithLine(left_x, left_y, x, y);
                    if (res > -1) {
                        if (killerActive) otherShip.destroyShip();
                        else {
                            processCollision(res, left_x, left_y, x, y, (byte)-30, (byte)1);
                            otherShip.processCollision(Constants.SHIP_LEFT_SIDE, rightPosX, rightPosY, posX, posY, (byte)30, (byte)0);
                          
                            impulseExchange(otherShip);
                          
                            return true;
                        }
                    }
                }
            }
            else if (controlType == Constants.SHIP_NPC) {
                frontShipDistance = Byte.MAX_VALUE;
                if ((posX - Constants.SHIP_DISTANCE) < right_x &&
                    (posX + Constants.SHIP_DISTANCE) > left_x &&
                    (rightPosY - Constants.SHIP_DISTANCE) < y && 
                    (posY + Constants.SHIP_DISTANCE) > left_y
                   ) {
                    // Alien ship inside radar area
                    if (left_y > posY) {
                        // Alien ship above this ship
                        frontShipDistance = (byte)(left_y - posY);
                        if (leftPosX < right_x && rightPosX > left_x) {
                            locationAlienShip = Constants.LOCATION_TOP_CENTER;
                          
                            if ((left_x < posX) && (posX < right_x)) isFrontTargetLocked = true;
                            else isFrontTargetLocked = false;
                        }
                        else if (right_x < leftPosX) locationAlienShip = Constants.LOCATION_TOP_LEFT;
                        else locationAlienShip = Constants.LOCATION_TOP_RIGHT;
                    }
                    else if (y < leftPosY) {
                        // Alien ship below this ship
                        frontShipDistance = (byte)(leftPosY - y);
                        if (leftPosX < right_x && rightPosX > left_x) {
                            locationAlienShip = Constants.LOCATION_BOTTOM_CENTER;
                               
                            if ((left_x < posX) && (posX < right_x)) isRearTargetLocked = true;
                            else isRearTargetLocked = false;
                        }
                        else if (right_x < leftPosX) locationAlienShip = Constants.LOCATION_BOTTOM_LEFT;
                        else locationAlienShip = Constants.LOCATION_BOTTOM_RIGHT;
                    }
                    else {
                        if (right_x < leftPosX) {
                            // Alien ship is on the left side
                            locationAlienShip = Constants.LOCATION_MIDDLE_LEFT;
                        }
                        else if (left_x > rightPosX) {
                            // Alien ship is on the right side
                            locationAlienShip = Constants.LOCATION_MIDDLE_RIGHT;
                        }
                    }
                }
            }
        }
        return false;
    }
   
/**************************************************************************************************/

    private void processCollision(byte shipSide, int aX, int aY, int bX, int bY, byte lineAngle, byte lineSide) {
        int tInt, offSetX;

        F_me = 0;
        step = 0;

        stopTurnEngine(Constants.SHIP_TURNSTATE_HITS);
        if (!wasHit) wasHit = true;

        angle = (byte)(((-angle + lineAngle)) + lineAngle);
        if (angle == 0) dir = Constants.DIRECTION_STRAIGHT;
        else if (angle > 0) dir = Constants.DIRECTION_RIGHT;
        else dir = Constants.DIRECTION_LEFT;
         
        angleDir = dir;

        if (angle > 90) {
            angle = 90;
        }
        else if (angle < -90) {
            angle = -90;
        }

        tInt = 0;
        // left ship's side hits border
        if (shipSide == Constants.SHIP_LEFT_SIDE) {
            // find cross point with left side
            tInt = GameScreen.getCrossPoint(posX, posY, leftPosX, leftPosY, aX, aY, bX, bY);
        }
        // right ship's side hits border
        else if(shipSide == Constants.SHIP_RIGHT_SIDE) {
            // find cross point with right side
            tInt = GameScreen.getCrossPoint(posX, posY, rightPosX, rightPosY, aX, aY, bX, bY);
        }

        offSetX = 0;
        // Correct ship possition
        if (lineSide == 0) { // The border on the left side of ship
            offSetX = ((tInt << 1) >> 17);
            //aPosY = (tInt & 0x0000ffff);

            offSetX -= leftPosX;
        }
        else if (lineSide == 1) { // The border on the right side of ship
            offSetX = ((tInt << 1) >> 17);
            //aPosY = (tInt & 0x0000ffff);

            offSetX -= rightPosX;
        }

        lPosX += GameScreen.fpToFP(offSetX);
        stepX += offSetX;
        posX += offSetX;

        // Decrease health of ship
        changeHealth(-GameScreen.fpToInt(GameScreen.fpMul(Constants.C_HIT_DAMAGE, V)));
    }

/**************************************************************************************************/

    private byte detectTrackItemsCollision() {
        int i, tPosY, aX, aY, bX, bY, saPosX, saPosY, sbPosX, sbPosY, minPosX;
        boolean flag;
        // Correct index of first track's item
        for (; (firstTrackItem < GameScreen.trackItems.length) && (GameScreen.trackItems[firstTrackItem].y < leftPosY); firstTrackItem++);
      
        saPosX = posX - (Constants.SHIP_RADAR_DISTANCE >> 1);
        saPosY = posY + (Constants.SHIP_RADAR_DISTANCE >> 1);
        sbPosX = saPosX + Constants.SHIP_RADAR_DISTANCE;
        sbPosY = posY;

        tPosY = posY + Constants.SHIP_RADAR_DISTANCE;
        minPosX = Integer.MAX_VALUE;
        for (i = firstTrackItem; (i < GameScreen.trackItems.length) && (GameScreen.trackItems[i].y < tPosY); i++) {
            if (GameScreen.trackItems[i].visible) {
                aX = GameScreen.trackItems[i].x + 3;
                aY = GameScreen.trackItems[i].y - 3;
                bX = aX + Constants.TRACK_ITEM_WIDTH - 6;
                bY = aY - Constants.TRACK_ITEM_HEIGHT + 6;
                flag = false;
                if (leftPosX < bX && rightPosX > aX && leftPosY < aY && posY > bY) {
                    if ((aX <= posX) && (posX <= bX)) {
                        // the track's item is in front of ship |<-/\->|
                        flag = true;
                    }
                    else if(posX < aX) {
                        // the track item is on the right side of ship /\ -> | |
                        flag = GameScreen.isIntersection(rightPosX, rightPosY, posX, posY, aX, bY, aX, aY);
                    }
                    else {
                        // the track item is on the left side of ship | | <- /\
                        flag = GameScreen.isIntersection(leftPosX, leftPosY, posX, posY, bX, bY, bX, aY);
                    }
                }
                else if (saPosX < bX && sbPosX > aX && sbPosY < aY && saPosY > bY) {
                    if (GameScreen.abs(posX - aX) < minPosX) {
                        nearestTrackItem = i;
                        minPosX = GameScreen.abs(posX - aX);
                    }
                }
                if (flag && !(controlType == Constants.SHIP_NPC && GameScreen.trackItems[i].type == Constants.ITEM_KILLER)) {
                    // Track's item was picked up
                    GameScreen.trackItems[i].visible = false;
                    return GameScreen.trackItems[i].type;
                }
            }
        }
        return -1;
    }

/**************************************************************************************************/

    private void updateShipEdges() {
        leftPosX  = posX - ((Constants.SHAPES[Constants.SHIP_SHAPES[type]][bodyState] >> 24) & 0xff);
        leftPosY  = posY - ((Constants.SHAPES[Constants.SHIP_SHAPES[type]][bodyState] >> 16) & 0xff);
        rightPosX = posX + ((Constants.SHAPES[Constants.SHIP_SHAPES[type]][bodyState] >> 8) & 0xff);
        rightPosY = posY - (Constants.SHAPES[Constants.SHIP_SHAPES[type]][bodyState] & 0xff);
    }

/**************************************************************************************************/
    public void startJump() {
        deactivateNitro();
        stopTurnEngine(Constants.SHIP_TURNSTATE_FREE);
        aBody.startAnimation(Constants.SHIP_JUMP_ANIMATIONS[type][bodyState], Constants.ANIMATION_PLAY_ONCE);
        moveMode = Constants.SHIP_MODE_JUMP;
    }

/**************************************************************************************************/

    public void destroyShip() {
        healthTimer.unSet();
        shieldTimer.unSet();
        nitroTimer.unSet();

        GameScreen.clearCheatCode();

        healthVisible = false;
        shieldActive = false;
        nitroActive = false;
        killerActive = false;

        step = 0;
        F_me = 0;
        stopBrakeEngine();
        stopTurnEngine(Constants.SHIP_TURNSTATE_FREE);
        F_me = 0;
        F_be = 0;
        A = 0;
        V = 0;
        dS = 0;
        stepX = 0;
        stepY = 0;

        //#if S40v1
            GameScreen.addExplosion(GameScreen.explosionFirstFreeIndex, Constants.A_EXPLOSION, posX, posY);
        //#else
            GameScreen.addExplosion(GameScreen.explosionFirstFreeIndex, Constants.A_EXPLOSION_BIG, posX, posY);
        //#endif

        shipVisible = false;
        healthTimer.set(700);
        shipState = Constants.SHIP_STATE_DESTROYED;
    }

/**************************************************************************************************/

    public void changeHealth(int value) {
        if (shipState != Constants.SHIP_STATE_DESTROYED && shipState != Constants.SHIP_STATE_REINIT && (value > 0 || !shieldActive)) {
            if (!healthTimer.isFinished()) healthTimer.unSet();
            healthTimer.set(1000);
            healthVisible = true;

            health += value;
            if (health > Constants.SHIP_HEALTH[type]) health = Constants.SHIP_HEALTH[type];
            else if(health <= 0) {
                health = 0;
                destroyShip();
            }
            healthMeterWidth = (byte)(Constants.HEALTH_METER_WIDTH - ((Constants.HEALTH_METER_WIDTH * health) / Constants.SHIP_HEALTH[type]));
        }
    }

/**************************************************************************************************/

    private void pickUpPowerUp(byte type) {
        if (itemType == Constants.ITEM_POWERUP && type == powerupType) {
            powerupCount ++;
            if (powerupCount > Constants.ITEM_MAX_COUNT) powerupCount = Constants.ITEM_MAX_COUNT;
        }
        else {
            itemType = Constants.ITEM_POWERUP;
            powerupType = type;
            powerupCount = 1;
        }
    }

    private void pickUpWeapon(byte type) {
        weaponCount = Constants.ITEM_MAX_COUNT;
        if (itemType != Constants.ITEM_WEAPON || weaponType != type) {
            itemType = Constants.ITEM_WEAPON;
            weaponType = type;
            activateWeapon();
        }
    }

/**************************************************************************************************/

    public void activatePowerUp() {
        if (itemType == Constants.ITEM_POWERUP && powerupCount > 0) {
            switch (powerupType) {
                case Constants.SPECIALITEM_SHIELD:
                    if (!shieldActive) {
                        if (!GameScreen.cheat_Shield) powerupCount--;
                        shieldActive = true;
                        aShield.startAnimation(Constants.A_SHIELD, Constants.ANIMATION_PLAY_REPEAT);
                        shieldTimer.set(Constants.SPECIALITEM_SHIELD_TIME);
                    }
                break;
                
                case Constants.SPECIALITEM_NITRO:
                    if ((!nitroActive) && (moveMode != Constants.SHIP_MODE_JUMP)) {
                        if (!GameScreen.cheat_Nitro) powerupCount--;
                        nitroActive = true;
                        F_nitro = Constants.F_NITRO;
                        nitroTimer.set(Constants.SPECIALITEM_NITRO_TIME);
                        aBody.changeAnimation(Constants.SHIP_NITRO_ANIMATIONS[type][bodyState]);
                    }
                break;
            }
        }
    }

/**************************************************************************************************/
   
    public void deactivateNitro() {
        nitroActive = false;
        F_nitro = 0;
        nitroTimer.unSet();
        aBody.changeAnimation(Constants.SHIP_ANIMATIONS[type][bodyState]);
    }

/**************************************************************************************************/
   
    public void move(long dt) {
        int index, tInt;
        byte shipSide;

        shooter.update();
        if (shooter.isEmpty()) shooter.stop();
     
        healthTimer.update();
        shieldTimer.update();

        switch (shipState) {
            case Constants.SHIP_STATE_READY:
            break;
            
            case Constants.SHIP_STATE_MOVE:
            case Constants.SHIP_STATE_FINISH:
            case Constants.SHIP_STATE_STOP:
                obstacleType = Constants.OBSTACLE_NONE;
                frontDistance = leftDistance = rightDistance = Byte.MAX_VALUE;
                nearestTrackItem = -1;
                borderInFrontIndex = -1;

                if (healthVisible && healthTimer.isFinished()) {
                    healthTimer.unSet();
                    healthVisible = false;
                }

                if (wasHit) {
                    wasHit = false;
                    turnengineIsWorking = true;
                    stopTurnEngine(Constants.SHIP_TURNSTATE_FREE);
                }

                if ((turnState == Constants.SHIP_TURNSTATE_MOVE) && (counter > 0) && (counter < ((Constants.SHIP_ANIMATIONS[type].length - 1) << Constants.SHIP_TS))) counter += dir;
                if (bodyState != (counter >> Constants.SHIP_TS)) {
                    bodyState = (byte)(counter >> Constants.SHIP_TS);

                    switch (moveMode) {
                        case Constants.SHIP_MODE_FLY:
                            aBody.changeAnimation(Constants.SHIP_ANIMATIONS[type][bodyState]);
                        break;
                        
                        case Constants.SHIP_MODE_JUMP:
                           aBody.changeAnimation(Constants.SHIP_JUMP_ANIMATIONS[type][bodyState]);
                        break;
                    }
                }

                if (aBody.updateAnimation(dt) && (moveMode == Constants.SHIP_MODE_JUMP)) {
                    aBody.startAnimation(Constants.SHIP_ANIMATIONS[type][bodyState], Constants.ANIMATION_PLAY_REPEAT);
                    moveMode = Constants.SHIP_MODE_FLY;
                }

                if (shieldActive) {
                    aShield.updateAnimation(dt);
                    if (shieldTimer.isFinished()) {
                        shieldTimer.unSet();
                        shieldActive = false;
                    }
                }

                if (nitroActive) {
                    nitroTimer.update();
                    if (nitroTimer.isFinished()) {
                        deactivateNitro();
                    }
                }

                if (killerActive) {
                    killerTimer.update();
                    if (killerTimer.isFinished()) {
                        killerActive = false;
                    }
                }

                if (((dir == Constants.DIRECTION_RIGHT) && (angle <= 90)) || ((dir == Constants.DIRECTION_LEFT) && (angle >= -90))) {
                    if ((turnState == Constants.SHIP_TURNSTATE_FREE) && ((angleDir * angle) > (angleDir * Constants.SHIP_ANGLE_STEP))) {
                        dir = Constants.DIRECTION_STRAIGHT;
                        angleDir = dir;
                        angle = 0;
                    }
                    else {
                        angle += angleDir * Constants.SHIP_ANGLE_STEP;
                    }
                    if (angle < turnMinAngle) {
                        angle = turnMinAngle;
                    }
                    else if (angle > turnMaxAngle) {
                        angle = turnMaxAngle;
                    }
                }

                switch (detectTrackItemsCollision()) {
                    case Constants.ITEM_MONEY_0:
                        money += 300;
                        //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                            if (controlType == Constants.SHIP_PLAYER) GameScreen.soundPlay(Constants.SOUND_BONUS_GEM);                         
                        //#endif                                                       
                    break;
                    
                    case Constants.ITEM_MONEY_1:
                        money += 650;
                        //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                            if(controlType == Constants.SHIP_PLAYER) GameScreen.soundPlay(Constants.SOUND_BONUS_GEM);                         
                        //#endif                                                       
                    break;
                  
                    case Constants.ITEM_MONEY_2:
                        money += 900;
                        //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                        	if(controlType == Constants.SHIP_PLAYER) GameScreen.soundPlay(Constants.SOUND_BONUS_GEM);                         
                        //#endif                                                       
                    break;
                    
                    case Constants.ITEM_HEALTH_0:
                        changeHealth(10);
                    break;
                  
                    case Constants.ITEM_HEALTH_1:
                        changeHealth(30);
                    break;
                    
                    case Constants.ITEM_KILLER:
                        killerActive = true;
                        killerTimer.set(Constants.SPECIALITEM_KILLER_TIME);
                    break;
                  
                    case Constants.ITEM_SHIELD:
                        pickUpPowerUp(Constants.SPECIALITEM_SHIELD);
                        if (!GameScreen.cheat_Shield) GameScreen.clearCheatCode();
                    break;

                    case Constants.ITEM_NITRO:
                        pickUpPowerUp(Constants.SPECIALITEM_NITRO);
                        if (!GameScreen.cheat_Nitro) GameScreen.clearCheatCode();
                    break;
                    
                    case Constants.ITEM_LASER:
                        pickUpWeapon(Constants.WEAPON_LASER);
                    break;
                  
                    case Constants.ITEM_ROCKET:
                        pickUpWeapon(Constants.WEAPON_ROCKET);
                        if (!GameScreen.cheat_Missiles) GameScreen.clearCheatCode();
                    break;
                  
                    case Constants.ITEM_BOMB:
                        pickUpWeapon(Constants.WEAPON_BOMB);
                        if (!GameScreen.cheat_Bomb) GameScreen.clearCheatCode();
                    break;
                  
                    case Constants.ITEM_MINE:
                        pickUpWeapon(Constants.WEAPON_MINE);
                        if (!GameScreen.cheat_Mine) GameScreen.clearCheatCode();
                    break;
                }

                dt = GameScreen.fpMul(GameScreen.fpToFP(dt), K);
               
                F_res = GameScreen.fpMul(C_res, GameScreen.fpMul(V, V));
                A = GameScreen.fpMul(F_me + F_nitro - F_be - F_res, m);
                V += GameScreen.fpMul(A, dt);
                if (V < 0) {
                    stopBrakeEngine();
                    V = 0;
                }
                dS = GameScreen.fpMul(V, dt);

                if (angle < 0) index = -angle;
                else index = angle;

                lPosX += dir * GameScreen.fpMul(GameScreen.sin[index], dS);
                stepX = GameScreen.fpToInt(lPosX) - posX;
                posX = GameScreen.fpToInt(lPosX);

                lPosY += GameScreen.fpMul(GameScreen.cos[index], dS);
                stepY = GameScreen.fpToInt(lPosY) - posY;
                posY = GameScreen.fpToInt(lPosY);

                updateShipEdges();

                if ((tInt = detectEdgeCollision()) != 0) {
                    index = tInt & 0x0000FFFF;
                    shipSide = (byte)((tInt >> 16) & 0x0000FFFF);
                  
                    switch (GameScreen.borders[index].type) {
                        case Constants.BORDER_TRACKEDGE:
                            processCollision(shipSide, GameScreen.borders[index].aPosX, GameScreen.borders[index].aPosY, GameScreen.borders[index].bPosX, GameScreen.borders[index].bPosY, GameScreen.borders[index].angle, GameScreen.borders[index].side);
                        break;
                     
                        case Constants.BORDER_WALL:
                            if (moveMode != Constants.SHIP_MODE_JUMP) {
                                destroyShip();
                                stepX = 0;
                                stepY = Constants.HIT_DELAY_STEP_Y;
                            }
                        break;
                     
                        case Constants.BORDER_JUMP:
                           if (moveMode != Constants.SHIP_MODE_JUMP) startJump();
                        break;
                    }
                }
            break;
            
            case Constants.SHIP_STATE_DESTROYED:
                if (healthTimer.isFinished()) {
                    healthTimer.unSet();
                  
                    init(posX, posY);

                    healthTimer.set(1200);
                    shieldTimer.set(100);

                    shipState = Constants.SHIP_STATE_REINIT;
                }
                else {
                    posX += stepX;
                    posY += stepY;
                }
            break;

            case Constants.SHIP_STATE_REINIT:
                if (shieldTimer.isFinished()) {
                    shieldTimer.unSet();
                    shipVisible = !shipVisible;
                    shieldTimer.set(100);
                }

                if (healthTimer.isFinished()) {
                    healthTimer.unSet();
                    shieldTimer.unSet();
                  
                    shipVisible = true;
                    shipState = Constants.SHIP_STATE_MOVE;
                    aBody.startAnimation(Constants.SHIP_ANIMATIONS[type][bodyState], Constants.ANIMATION_PLAY_REPEAT);
                }
            break;
        }
    }

/**************************************************************************************************/

}